package com.tedu.api.io;

import org.junit.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**IO流：传输数据
 *File文件，文件夹类：无法读写数据
 *RandomAccessFile:读写按照字节，读写类不明确，靠构造器传入第二个参数确定
 *
 *Java 提出一套标准 IO--读写单独提供类
 * ①方向区别：
 * 输入流---(读：针对文件，文件往程序中走，文件“相对于程序”)
 * 输出流---(写：针对文件，文件往程序写出，文件“相对于程序”)
 * 输入流和输出流创建方式？
 * 输入流 InputStream(抽象类)---顶级父类---读操作
 * 输出流 OutputStream(抽象类)---顶级父类---写操作
 * 以上两个流定义所有流具备读写操作，本身无法实例化
 * ②按照功能进行区别：
 * 低级流：专门搬运数据的流
 * FileInputStream 文件输入流：读操作  ---InputStream(抽象类)
 * OutputStream    文件输出流：写操作  ---OutputStream (抽象类)
 * 功能：建立在程序于数据源之间的“管道”，所有数据传输通过低级流【节点流】
 * 高级流：不能独立存在的流【叫做处理流】
 *        处理低级流的书记，并且可以被其他高级流处理
 *
 * --------------流：明确功能，创建对象：直接使用低级流--高级流创建
 */
public class IOAPI {
    @Test
    public void testIO() throws IOException {
        //创建标准IO流：方向划分：输入流等于输出流--功能：低级流【节点流】
        //需求：从项目中写出“fox.txt” 低级流：FileOutputStream
        //创建文件输出流
        //抛出异常FileNotFoundException：没有文件的异常！
        //原因：路径或者文件名写错
        FileOutputStream fos=new FileOutputStream("fos.txt");
        /**
         * 输出一句话：我
         * write(字符串)  返回值：void
         * 作用：写出一个文件内容：字节数组
         * 抛出异常  IOException   IO流异常：写出失败
         */
        //String 字符串 方法：getBytes() 可以将字符串转换成字符串数组 char[]
        fos.write("我们是祖国的花朵".getBytes());
        //标准IO流必须关闭
        fos.close();//释放流：避免内存占用
    }
    /**
     * FileOutputStream实现类----构造器使用方法
     * new FileOutputStream(String path,boolean append)
     * 通过第二个步骤，确定数据是否追加，true代表追加，反之
     * new FileOutputStream(File file,boolean append)
     */

    @Test
    public void testIOA() throws IOException {
        //当前API 项目 下添加fos.txt--增加功能：追加效果
        //编写相对路径：./fos.txt   直接写文件|不写./ 都是当前目录下
        FileOutputStream fos=
        new FileOutputStream("for.txt",true);
        String str="你好,你好,你好你好你好";
        fos.write(str.getBytes());
        //关闭流
        fos.close();
    }

    /**低级流
     * 文件输入流
     * FileInputStream
     * read() 返回值：int
     * 作用：读取到一个字节的信息
     */
    @Test
    public void testInputStream() throws IOException {
        //创建文件输入流---读入
        //RandomAccessFile raf=
        //       new RandomAccessFile("fos.txt","r")
        FileInputStream fis=
                new FileInputStream("fos.txt");
        //10KB 字节数组  [不想看到整数值]
        byte[] bytes=new byte[1024*10];
        //10KB 读 数据  [不想看到整数值]
        int len=fis.read(bytes);
        //String字符串类--提供构造器方法:按照字节数组量，输出字符串
        //String构造器 new String(字节数组，开始读取文件，结束读取文件);
        //将【二进制值】整数 转换为 字符串
        String str=new String(bytes,0,len);
        System.out.println("打印读"+str);
        fis.close();
    }
    //需求：【标准IO】重构RandomAccessFile类-复制视频的方法
    @Test
    public void testWork() throws IOException {
        //1.创建输入流 --读--    被复制文件【源文件】
        FileInputStream fis=new FileInputStream("复制文件.mp4");
        //2.创建输出流 --写--   复制品
        FileOutputStream fos=new FileOutputStream("IO.mp4");
        //3.用于保存读取到的字节量
        int len=-1;//①保存读取的数据值【可以被覆盖】②-1代表文件结尾
        //6.视频空间大，解决方案：10KB 字节数组：设定保存值10KB
        byte[] bytes=new byte[1024*10];
        //4.一直读取文件，保存len中，如果结构不等于-1 一直读
        //(len=fis.read(bytes))!=-1
        long start=System.currentTimeMillis();//开始毫秒数
        while ((len=fis.read(bytes))!=-1){
            //4.1将读取到的文件写出
            fos.write(bytes,0,len);
        }
     long end=System.currentTimeMillis();//结束毫秒数
        System.out.println("测试传输时间"+(end-start)+"毫秒");
        //5.关闭流
        fis.close();
        fos.close();

    }

    /**
     * 高级流【处理流】；处理低级流以及其他高级流的一”种“流
     * 高级流不能独立存在，一定处理低级流
     * BufferedInputStream---高级流：快速读   缓冲输入流
     * BufferedOutputStream--高级流：快速写   缓冲输出流
     * 以上两个高级流：内嵌一套按照实际传输数据大小，随机型改变的字节数组
     * 高级流语法：
     * BufferedInputStream bis=new BufferedInputStream【低级流引用】
     * 需求：视频 使用IO流【低级流加高级流】--实现视频快速复制
     */
    @Test
    public void testCV() throws IOException {
        //创建低级流：输入流，输出流
       FileInputStream fis=new FileInputStream("复制文件.mp4");
        BufferedInputStream bis=new BufferedInputStream(fis);
       FileOutputStream fos=new FileOutputStream("缓冲文件");
        BufferedOutputStream bos=new BufferedOutputStream(fos);
      //2.定义整数变量保存每次读取的字节量
        int len=-1;
      //3.将高级流:缓冲输入流--读取的数据--保存交给len,结果不等于-1
        //(len=bis.read())!=-1
        long start=System.currentTimeMillis();
        while((len=bis.read())!=-1){
            bos.write(len);
        }
        long end=System.currentTimeMillis();
        System.out.println("缓冲花费时间"+(end-start));
        //4.关闭流
        fis.close();
        fos.close();
    }

    /**【高级流：处理流】
     * BufferedOutputStream 缓冲输出流
     * 需求：写出一份文件：bos.txt,写出：一段文本内容
     *
     */
@Test
    public void testBOS() throws IOException {
    //创建低级流--写出bos.txt
  FileOutputStream fos=new FileOutputStream("bos.txt");
    //创建高级流--写出一段文本内容【缓冲区：字节数组】
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    String str="你好,你好,你好你好你好";
    //write()bos.write(byte[] b); 作用：写出字节数组
    bos.write(str.getBytes());
    /**
     *   str数据量小  缓冲区大   强制送出
     *     45人       车100     晚上9
     * flush()
     *作用：可以强制将内部缓冲区数据一次性读写
     * 缺点：频繁使用flush降低读写
     */
    //bos.flush();
    bos.close();
    fos.close();
    /**
     * 标准IO 必须与   异常 存在 ----“传输数据”保障数据安全【处理异常】
     * 异常重点：1.认识代码中抛出异常【查API】，异常产生原因！
     *          2.异常处理---【快捷键Ctrl+alt+t】
     *          语法：try{
     *              怀疑可能有错误或者已经提示异常
     *          }catch(小异常名 e){
     *              e.print();  //打印异常信息----通过异常信息解决问题
     *          }catch(中异常名 e){   catch可以捕获很多异常：小到大
     *
     *          }finally{
     *              一定执行代码块
     *          }
     *
     *    低级流;FileOutputStream 文件输出流--写出
     *          FileInputStream  文件输入流--读入
     *    高级流;BufferedOutputStream 缓冲输出流--
     *          BufferedInputStream  缓冲输入流--
     *
     *          考试题：final与finally的区别？
     *              final关键字：修饰 变量、方法、类--->变量成常量
     *                                              方法不能重写
     *                                              类不能继承
     *              finally关键字：异常处理机制中：捕获异常
     *                     finally在捕获异常中，可以写，也可以不写
     *     与finally关键字所有异常都不符合，一定会执行的语法块
     *     通常使用在IO流中：关闭流为主！  关闭高级流-->间接关闭低级流
     *
     *     需求：BOS高级流---重新结合异常--->标准IO流
     */}
@Test
    public void testBOSO() {
        //1.需要将流置空：置空--①覆盖，不用多次创建！②关闭流
        FileOutputStream fos=null;//低级流--搬运数据：写出
        BufferedOutputStream bos=null;//高级流--处理低级流：缓冲输出流
        //2.捕获异常操作：快捷键Ctrl+alt+t：怀疑IO流代码-->捕获异常
        //2.1 创建输出流
        try {
            fos=new FileOutputStream("BOS标准流写法.txt");
            bos=new BufferedOutputStream(fos);
            //3.高级流：缓冲输出流---功能：缓冲区【字节数组】  写出数据
            bos.write("标准流写法".getBytes());
            //4.缓冲区：数据量比较小---采用flush()  数据一次性写出
            bos.flush();
        } catch(FileNotFoundException e){//文件不存在异常：路径写错，文件不存在
            e.printStackTrace();//打印异常信息
            System.out.println("【小】文件不存在异常");
        }catch (IOException e) {  //IO流最大异常：小异常不处理
            e.printStackTrace();
            System.out.println("【中】IO流异常");
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("【大】异常");
        } finally {
      //一定执行代码块：IO流关闭--高级流--关闭高级流--低级流关闭【捕获异常】
      //                       低级流--关闭低级流【捕获异常】
      //5.先判断，高级流--是否为空【有没有高级流对象】--有高级流对象
      //                                         没有高级流对象
        if (bos!=null)
            try{
             bos.close();
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
@Test
public void testOUT() {
    FileOutputStream gos=null;
    BufferedOutputStream hos=null;
    try {
        gos=new FileOutputStream("BOS标准流写法.txt");
        hos=new BufferedOutputStream(gos);
    } catch(FileNotFoundException e){//文件不存在异常：路径写错，文件不存在
        e.printStackTrace();//打印异常信息
        System.out.println("异常");
    } finally {
        if (hos!=null)
        try{
            hos.close();
        } catch (IOException e){
            e.printStackTrace();
        }
    }


}
}





















































